﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SsrsRenderStudio.Shared;
using SsrsRenderStudio.Shared.Windows32API;
using SsrsRenderStudio.Shared.HostServices;

namespace SsrsRenderStudio.Wcf.Services
{
    public static class DeviceContextCache
    {
        private class CachedDeviceContext
        {
            public CachedDeviceContext(DeviceContextCachingParameters parameters, IntPtr handle, Action<string, IntPtr> removeSelfFunc)
            {
                //warning: if a null action is passed then the item will NEVER leave cache
                _removeSelfFunc = removeSelfFunc;
                CachingParameters = parameters;
                DeviceContextHandle = handle;
                
                Logger.Log("60000", CachingParameters.NetworkDestination, CachingParameters.CacheTimeToLive.ToString());
                _expirationTimer = new System.Timers.Timer();
                _expirationTimer.Elapsed += new System.Timers.ElapsedEventHandler(_expirationTimer_Elapsed);
                startTimer();
            }

            void _expirationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                _expirationTimer.Close();
                _removeSelfFunc(CachingParameters.NetworkDestination, DeviceContextHandle);
                Logger.Log("60001", CachingParameters.NetworkDestination);
            }

            public DeviceContextCachingParameters CachingParameters { get; private set; }
            public IntPtr DeviceContextHandle { get; private set; }
            private System.Timers.Timer _expirationTimer;
            private Action<string, IntPtr> _removeSelfFunc;

            private void startTimer()
            {
                _expirationTimer.Stop();
                _expirationTimer.Interval = CachingParameters.CacheTimeToLive.TotalMilliseconds;
                _expirationTimer.AutoReset = false;
                _expirationTimer.Start();
            }

            public void ExtendExpiry()
            {
                Logger.Log("60002", CachingParameters.NetworkDestination, CachingParameters.CacheTimeToLive.ToString()); 
                startTimer();
            }
        }

        private static Dictionary<string, CachedDeviceContext> _cache = new Dictionary<string, CachedDeviceContext>();

        public static DeviceContextCachingInformation Get(DeviceContextCachingParameters cacheParameters)
        {
            if (cacheParameters.IsCachingEnabled && cacheParameters.CacheTimeToLive != TimeSpan.Zero)
            {
                if (!_cache.ContainsKey(cacheParameters.NetworkDestination))
                {
                    IntPtr dc = createDeviceContext(cacheParameters.NetworkDestination);
                    if (dc == IntPtr.Zero)
                        return new DeviceContextCachingInformation { DeviceContextHandle = IntPtr.Zero, IsValid = false, WasCached = false };

                    _cache.Add(cacheParameters.NetworkDestination, new CachedDeviceContext(cacheParameters, dc, removeItemFromCache));
                }
                else
                {
                    _cache[cacheParameters.NetworkDestination].ExtendExpiry();
                }

                return new DeviceContextCachingInformation { DeviceContextHandle = _cache[cacheParameters.NetworkDestination].DeviceContextHandle, IsValid = true, WasCached = true };
            }
            else
            {
                IntPtr dc = createDeviceContext(cacheParameters.NetworkDestination);
                return new DeviceContextCachingInformation { DeviceContextHandle = dc, IsValid = ((dc == IntPtr.Zero) ? false : true), WasCached = false };
            }
        }

        private static void removeItemFromCache(string networkDestination, IntPtr deviceContextHandle)
        {
            deleteDeviceContext(networkDestination, deviceContextHandle);
            _cache.Remove(networkDestination);
        }

        public static void PurgeCache()
        {
            foreach (var key in _cache.Keys)
            {
                deleteDeviceContext(key, _cache[key].DeviceContextHandle);
            }

            _cache.Clear();
            _cache = new Dictionary<string, CachedDeviceContext>();
        }

        private static IntPtr createDeviceContext(string networkDestination)
        {
            IntPtr dc = GDIWrapper.CreatePrinterDeviceContext(networkDestination);

            if (IntPtr.Zero == dc)
            {
                Logger.Log("30000", networkDestination);
                return IntPtr.Zero;
            }

            Logger.Log("60003", networkDestination);
          
            return dc;
        }

        private static void deleteDeviceContext(string networkDestination, IntPtr deviceContextHandle)
        {
            try { GDI.DeleteDC(deviceContextHandle); }
            catch { }
            Logger.Log("60004", networkDestination);
        }
    }
}
